Use GtkCssValue in symbolic color resolving
authorAlexander Larsson <alexl@redhat.com>
Thu, 8 Mar 2012 13:52:10 +0000 (14:52 +0100)
committerAlexander Larsson <alexl@redhat.com>
Thu, 8 Mar 2012 13:52:10 +0000 (14:52 +0100)
We now store the symbolic colors as a GtkCssValue which means that
we can reuse the color when resolving and storing the color in
the computed values in the style context.

Additionally we keep a last_resolved GtkCssValue cache in the
GtkSymbolicColor, and if resolving the color returns the same as
last time we reuse the old value. This further increases sharing
of Css Values.

gtk/gtkcssstylefuncs.c
gtk/gtkcssstylepropertyimpl.c
gtk/gtkstylecontext.c
gtk/gtkstylecontextprivate.h
gtk/gtksymboliccolor.c
gtk/gtksymboliccolorprivate.h

index b1e373e82aaff9e29bb570584a913f05dc944194..0693e04487f5468bb496a3bb57c5a7e6084110e3 100644 (file)
@@ -215,7 +215,8 @@ static GtkCssValue *
 rgba_value_compute (GtkStyleContext *context,
                     GtkCssValue    *specified)
 {
-  GdkRGBA rgba, white = { 1, 1, 1, 1 };
+  GdkRGBA white = { 1, 1, 1, 1 };
+  GtkCssValue *res;
   
   if (_gtk_css_value_holds (specified, GTK_TYPE_CSS_SPECIAL_VALUE))
     {
@@ -227,12 +228,13 @@ rgba_value_compute (GtkStyleContext *context,
 
       if (symbolic == _gtk_symbolic_color_get_current_color ())
         return _gtk_css_value_ref (_gtk_style_context_peek_property (context, "color"));
-      else if (_gtk_style_context_resolve_color (context,
-                                                 symbolic,
-                                                 &rgba))
-       return _gtk_css_value_new_from_rgba (&rgba);
-      else
+      else {
+       res = _gtk_style_context_resolve_color_value (context, symbolic);
+       if (res != NULL)
+         return res;
+
        return _gtk_css_value_new_from_rgba (&white);
+      }
     }
   else
     return _gtk_css_value_ref (specified);
index 5d206e3be3d6dceb524e6464b4577c6e78cfa98e..f6d4b491f3c75acacb32f7c4919ea19c3402844d 100644 (file)
@@ -146,7 +146,7 @@ color_compute (GtkCssStyleProperty    *property,
                GtkCssValue            *specified)
 {
   GtkSymbolicColor *symbolic = _gtk_css_value_get_symbolic_color (specified);
-  GdkRGBA rgba;
+  GtkCssValue *resolved;
 
   if (symbolic == _gtk_symbolic_color_get_current_color ())
     {
@@ -170,11 +170,10 @@ color_compute (GtkCssStyleProperty    *property,
           return _gtk_css_value_ref (_gtk_style_context_peek_property (context, "color"));
         }
     }
-  else if (_gtk_style_context_resolve_color (context,
-                                             symbolic,
-                                             &rgba))
+  else if ((resolved = _gtk_style_context_resolve_color_value (context,
+                                                              symbolic)) != NULL)
     {
-      return _gtk_css_value_new_from_rgba (&rgba);
+      return resolved;
     }
   else
     {
index 42673c3dead7fbc8378d740ad8d2a067941819b6..e04e03b452cf46175a09da94ad2b273c8d2a2252 100644 (file)
@@ -2919,19 +2919,39 @@ gtk_style_context_color_lookup_func (gpointer    contextp,
   return sym_color;
 }
 
+GtkCssValue *
+_gtk_style_context_resolve_color_value (GtkStyleContext  *context,
+                                       GtkSymbolicColor *color)
+{
+  g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
+  g_return_val_if_fail (color != NULL, FALSE);
+
+  return _gtk_symbolic_color_resolve_full (color,
+                                           gtk_style_context_color_lookup_func,
+                                           context);
+}
+
+
 gboolean
 _gtk_style_context_resolve_color (GtkStyleContext  *context,
                                   GtkSymbolicColor *color,
                                   GdkRGBA          *result)
 {
+  GtkCssValue *val;
+
   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), FALSE);
   g_return_val_if_fail (color != NULL, FALSE);
   g_return_val_if_fail (result != NULL, FALSE);
 
-  return _gtk_symbolic_color_resolve_full (color,
-                                           gtk_style_context_color_lookup_func,
-                                           context,
-                                           result);
+  val = _gtk_symbolic_color_resolve_full (color,
+                                         gtk_style_context_color_lookup_func,
+                                         context);
+  if (val == NULL)
+    return FALSE;
+
+  *result = *_gtk_css_value_get_rgba (val);
+  _gtk_css_value_unref (val);
+  return TRUE;
 }
 
 /**
index 06efa0f83baf8a82fc4ee6e516b1c9843429fd70..dbec998443785ec91a86eaf85bb107e3ca494b03 100644 (file)
@@ -41,6 +41,8 @@ gboolean       _gtk_style_context_check_region_name          (const gchar     *s
 gboolean       _gtk_style_context_resolve_color              (GtkStyleContext  *context,
                                                               GtkSymbolicColor *color,
                                                               GdkRGBA          *result);
+GtkCssValue *  _gtk_style_context_resolve_color_value        (GtkStyleContext  *context,
+                                                              GtkSymbolicColor *color);
 void           _gtk_style_context_get_cursor_color           (GtkStyleContext *context,
                                                               GdkRGBA         *primary_color,
                                                               GdkRGBA         *secondary_color);
index bb4c2b8e898e6202e1d1a0f2ceda974cd36a1c30..b96a2348fdaf16c0c9a04e7138602a34933edf15 100644 (file)
@@ -58,10 +58,10 @@ struct _GtkSymbolicColor
 {
   ColorType type;
   guint ref_count;
+  GtkCssValue *last_value;
 
   union
   {
-    GdkRGBA color;
     gchar *name;
 
     struct
@@ -104,7 +104,7 @@ gtk_symbolic_color_new_literal (const GdkRGBA *color)
 
   symbolic_color = g_slice_new0 (GtkSymbolicColor);
   symbolic_color->type = COLOR_TYPE_LITERAL;
-  symbolic_color->color = *color;
+  symbolic_color->last_value = _gtk_css_value_new_from_rgba (color);
   symbolic_color->ref_count = 1;
 
   return symbolic_color;
@@ -328,27 +328,28 @@ gtk_symbolic_color_unref (GtkSymbolicColor *color)
 
   if (color->ref_count == 0)
     {
+      _gtk_css_value_unref (color->last_value);
       switch (color->type)
-        {
-        case COLOR_TYPE_NAME:
-          g_free (color->name);
-          break;
-        case COLOR_TYPE_SHADE:
-          gtk_symbolic_color_unref (color->shade.color);
-          break;
-        case COLOR_TYPE_ALPHA:
-          gtk_symbolic_color_unref (color->alpha.color);
-          break;
-        case COLOR_TYPE_MIX:
-          gtk_symbolic_color_unref (color->mix.color1);
-          gtk_symbolic_color_unref (color->mix.color2);
-          break;
-        case COLOR_TYPE_WIN32:
-          g_free (color->win32.theme_class);
-          break;
-        default:
-          break;
-        }
+       {
+       case COLOR_TYPE_NAME:
+         g_free (color->name);
+         break;
+       case COLOR_TYPE_SHADE:
+         gtk_symbolic_color_unref (color->shade.color);
+         break;
+       case COLOR_TYPE_ALPHA:
+         gtk_symbolic_color_unref (color->alpha.color);
+         break;
+       case COLOR_TYPE_MIX:
+         gtk_symbolic_color_unref (color->mix.color1);
+         gtk_symbolic_color_unref (color->mix.color2);
+         break;
+       case COLOR_TYPE_WIN32:
+         g_free (color->win32.theme_class);
+         break;
+       default:
+         break;
+       }
 
       g_slice_free (GtkSymbolicColor, color);
     }
@@ -560,106 +561,155 @@ resolve_lookup_color (gpointer data, const char *name)
  **/
 gboolean
 gtk_symbolic_color_resolve (GtkSymbolicColor   *color,
-                            GtkStyleProperties *props,
-                            GdkRGBA            *resolved_color)
+                           GtkStyleProperties *props,
+                           GdkRGBA            *resolved_color)
 {
+  GtkCssValue *v;
+
   g_return_val_if_fail (color != NULL, FALSE);
   g_return_val_if_fail (resolved_color != NULL, FALSE);
   g_return_val_if_fail (props == NULL || GTK_IS_STYLE_PROPERTIES (props), FALSE);
 
-  return _gtk_symbolic_color_resolve_full (color,
-                                           resolve_lookup_color,
-                                           props,
-                                           resolved_color);
+  v =_gtk_symbolic_color_resolve_full (color,
+                                      resolve_lookup_color,
+                                      props);
+  if (v == NULL)
+    return FALSE;
+
+  *resolved_color = *_gtk_css_value_get_rgba (v);
+  _gtk_css_value_unref (v);
+  return TRUE;
 }
 
-gboolean
+GtkCssValue *
 _gtk_symbolic_color_resolve_full (GtkSymbolicColor           *color,
-                                  GtkSymbolicColorLookupFunc  func,
-                                  gpointer                    data,
-                                  GdkRGBA                    *resolved_color)
+                                 GtkSymbolicColorLookupFunc  func,
+                                 gpointer                    data)
 {
+  GtkCssValue *value;
+
   g_return_val_if_fail (color != NULL, FALSE);
-  g_return_val_if_fail (resolved_color != NULL, FALSE);
   g_return_val_if_fail (func != NULL, FALSE);
 
+  value = NULL;
   switch (color->type)
     {
     case COLOR_TYPE_LITERAL:
-      *resolved_color = color->color;
-      return TRUE;
+      return _gtk_css_value_ref (color->last_value);
     case COLOR_TYPE_NAME:
       {
-        GtkSymbolicColor *named_color;
+       GtkSymbolicColor *named_color;
 
-        named_color = func (data, color->name);
+       named_color = func (data, color->name);
 
-        if (!named_color)
-          return FALSE;
+       if (!named_color)
+         return NULL;
 
-        return _gtk_symbolic_color_resolve_full (named_color, func, data, resolved_color);
+       return _gtk_symbolic_color_resolve_full (named_color, func, data);
       }
 
       break;
     case COLOR_TYPE_SHADE:
       {
-        GdkRGBA shade;
+       GtkCssValue *val;
+       GdkRGBA shade;
 
-        if (!_gtk_symbolic_color_resolve_full (color->shade.color, func, data, &shade))
-          return FALSE;
+       val = _gtk_symbolic_color_resolve_full (color->shade.color, func, data);
+       if (val == NULL)
+         return NULL;
 
-        _shade_color (&shade, color->shade.factor);
-        *resolved_color = shade;
+       shade = *_gtk_css_value_get_rgba (val);
+       _shade_color (&shade, color->shade.factor);
 
-        return TRUE;
+       _gtk_css_value_unref (val);
+
+       value = _gtk_css_value_new_from_rgba (&shade);
       }
 
       break;
     case COLOR_TYPE_ALPHA:
       {
-        GdkRGBA alpha;
+       GtkCssValue *val;
+       GdkRGBA alpha;
+
+       val = _gtk_symbolic_color_resolve_full (color->alpha.color, func, data);
+       if (val == NULL)
+         return NULL;
 
-        if (!_gtk_symbolic_color_resolve_full (color->alpha.color, func, data, &alpha))
-          return FALSE;
+       alpha = *_gtk_css_value_get_rgba (val);
+       alpha.alpha = CLAMP (alpha.alpha * color->alpha.factor, 0, 1);
 
-        *resolved_color = alpha;
-        resolved_color->alpha = CLAMP (alpha.alpha * color->alpha.factor, 0, 1);
+       _gtk_css_value_unref (val);
 
-        return TRUE;
+       value = _gtk_css_value_new_from_rgba (&alpha);
       }
+      break;
+
     case COLOR_TYPE_MIX:
       {
-        GdkRGBA color1, color2;
+       GtkCssValue *val;
+       GdkRGBA color1, color2, res;
 
-        if (!_gtk_symbolic_color_resolve_full (color->mix.color1, func, data, &color1))
-          return FALSE;
+       val = _gtk_symbolic_color_resolve_full (color->mix.color1, func, data);
+       if (val == NULL)
+         return NULL;
+       color1 = *_gtk_css_value_get_rgba (val);
+       _gtk_css_value_unref (val);
 
-        if (!_gtk_symbolic_color_resolve_full (color->mix.color2, func, data, &color2))
-          return FALSE;
+       val = _gtk_symbolic_color_resolve_full (color->mix.color2, func, data);
+       if (val == NULL)
+         return NULL;
+       color2 = *_gtk_css_value_get_rgba (val);
+       _gtk_css_value_unref (val);
 
-        resolved_color->red = CLAMP (color1.red + ((color2.red - color1.red) * color->mix.factor), 0, 1);
-        resolved_color->green = CLAMP (color1.green + ((color2.green - color1.green) * color->mix.factor), 0, 1);
-        resolved_color->blue = CLAMP (color1.blue + ((color2.blue - color1.blue) * color->mix.factor), 0, 1);
-        resolved_color->alpha = CLAMP (color1.alpha + ((color2.alpha - color1.alpha) * color->mix.factor), 0, 1);
 
-        return TRUE;
+       res.red = CLAMP (color1.red + ((color2.red - color1.red) * color->mix.factor), 0, 1);
+       res.green = CLAMP (color1.green + ((color2.green - color1.green) * color->mix.factor), 0, 1);
+       res.blue = CLAMP (color1.blue + ((color2.blue - color1.blue) * color->mix.factor), 0, 1);
+       res.alpha = CLAMP (color1.alpha + ((color2.alpha - color1.alpha) * color->mix.factor), 0, 1);
+
+       value =_gtk_css_value_new_from_rgba (&res);
       }
 
       break;
     case COLOR_TYPE_WIN32:
-      return _gtk_win32_theme_color_resolve (color->win32.theme_class,
+      {
+       GdkRGBA res;
+
+       if (!_gtk_win32_theme_color_resolve (color->win32.theme_class,
                                             color->win32.id,
-                                            resolved_color);
+                                            &res))
+         return NULL;
+
+       value = _gtk_css_value_new_from_rgba (&res);
+      }
 
       break;
     case COLOR_TYPE_CURRENT_COLOR:
-      return FALSE;
+      return NULL;
       break;
     default:
       g_assert_not_reached ();
     }
 
-  return FALSE;
+  if (value != NULL)
+    {
+      if (color->last_value != NULL &&
+         gdk_rgba_equal (_gtk_css_value_get_rgba (color->last_value),
+                         _gtk_css_value_get_rgba (value)))
+       {
+         _gtk_css_value_unref (value);
+         value = _gtk_css_value_ref (color->last_value);
+       }
+      else
+       {
+         if (color->last_value != NULL)
+           _gtk_css_value_unref (color->last_value);
+         color->last_value = _gtk_css_value_ref (value);
+       }
+    }
+
+  return value;
 }
 
 /**
@@ -684,7 +734,7 @@ gtk_symbolic_color_to_string (GtkSymbolicColor *color)
   switch (color->type)
     {
     case COLOR_TYPE_LITERAL:
-      s = gdk_rgba_to_string (&color->color);
+      s = gdk_rgba_to_string (_gtk_css_value_get_rgba (color->last_value));
       break;
     case COLOR_TYPE_NAME:
       s = g_strconcat ("@", color->name, NULL);
index a469626cc970603016f9845411eb3b828fd7b592..869af698a972d5e5b44b9cfc8161e664a5dc88d6 100644 (file)
 #define __GTK_SYMBOLIC_COLOR_PRIVATE_H__
 
 #include "gtk/gtksymboliccolor.h"
+#include "gtk/gtkcssvalueprivate.h"
 
 G_BEGIN_DECLS
 
 typedef GtkSymbolicColor * (* GtkSymbolicColorLookupFunc) (gpointer data, const char *name);
 
-gboolean           _gtk_symbolic_color_resolve_full       (GtkSymbolicColor           *color,
+GtkCssValue *      _gtk_symbolic_color_resolve_full       (GtkSymbolicColor           *color,
                                                            GtkSymbolicColorLookupFunc  func,
-                                                           gpointer                    data,
-                                                           GdkRGBA                    *resolved_color);
+                                                           gpointer                    data);
 
 GtkSymbolicColor * _gtk_symbolic_color_get_current_color  (void);